<!--
 * Copyright © 2023
 * @Author: zhangxiang
 * @Date: 2023-07-23 14:41:28
 * @LastEditors: zhangxiang
 * @LastEditTime: 2023-08-21 09:32:51
 * @Description:
 *
-->

<template>
  <div class="nsg-form-ctn">
    <el-form
      ref="form"
      class="form"
      :rules="rules"
      :model="form"
      label-width="auto"
      size="medium"
    >
      <el-form-item
        v-if="scene != 'orchestrate'"
        class="item"
        label="云服务商"
        prop="cloudProvider"
      >
        <el-select
          v-model="form.cloudProvider"
          placeholder="请选择云服务商"
          style="width: 100%"
          :disabled="true"
        >
          <el-option
            v-for="item in cloudProviderOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item
        v-if="scene != 'orchestrate'"
        class="item right"
        label="云账户"
        prop="cloudAccountName"
      >
        <el-select
          v-model="form.cloudAccountName"
          placeholder="请选择云账户"
          style="width: 100%"
          no-data-text="请先选择合适的云服务商"
          :loading="loadingCloudAccountName"
          @change="cloudAccountNameChange"
        >
          <el-option
            v-for="item in cloudAccountNameOptions"
            :key="item.cloudAccountName"
            :label="item.cloudAccountName"
            :value="item.cloudAccountName"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="安全组名称" prop="name">
        <el-row type="flex" align="middle">
          <el-input v-model="form.name" placeholder="请输入安全组名称" />
          <el-popover placement="right" width="250" trigger="hover">
            <p v-html="nameRule"></p>
            <i
              slot="reference"
              class="el-icon-info icon"
              style="font-size: 18px; margin-left: 10px"
            ></i>
          </el-popover>
        </el-row>
      </el-form-item>
      <el-form-item
        v-if="
          form.cloudProvider === '阿里云' || form.cloudProvider === '华为云'
        "
        label="区域"
        prop="cpRegionId"
      >
        <el-select
          v-model="form.cpRegionId"
          placeholder="请选择区域"
          no-data-text="请选择合适的云服务商"
          style="width: 100%"
        >
          <el-option
            v-for="item in regionOptions"
            :key="item.cpId"
            :label="item.desc"
            :value="item.cpId"
          />
        </el-select>
      </el-form-item>
      <!-- <el-form-item
        v-if="form.cloudProvider === '阿里云'"
        label="网络"
        prop="cpVpcId"
      >
        <el-select
          v-model="form.cpVpcId"
          placeholder="请选择网络"
          style="width: 100%"
          no-data-text="请先选择合适的区域"
        >
          <el-option
            v-for="item in networkOptions"
            :key="item.cpId"
            :label="item.name"
            :value="item.cpId"
          />
        </el-select>
      </el-form-item> -->
      <el-form-item label="描述" prop="desc">
        <el-input
          v-model="form.desc"
          placeholder="请输入描述"
          type="textarea"
          :rows="2"
          :resize="'none'"
        />
      </el-form-item>
    </el-form>

    <el-tabs v-model="activeTab">
      <el-tab-pane label="入栈规则" name="push" />
      <el-tab-pane label="出栈规则" name="pop" />
    </el-tabs>
    <div class="rule-wrapper">
      <el-button
        style="margin-bottom: 10px"
        plain
        icon="el-icon-plus"
        size="small"
        @click="addRule"
      >
        添加</el-button>
      <div class="row title">
        <div class="item item1">授权策略</div>
        <div class="item item2">协议类型</div>
        <div class="item item3">端口范围</div>
        <div class="item item4">授权对象</div>
        <div class="item item5">操作</div>
      </div>
      <div v-for="(rule, index) in currentRules" :key="index" class="row">
        <div class="item item1">
          <el-select
            v-model="rule.policy"
            placeholder="请选择"
            style="width: 90%"
            size="mini"
          >
            <el-option
              v-for="item in policyOptions"
              :key="item.label"
              :label="item.label"
              :value="item.value"
              :disabled="isCloudPrivate && item.value == '拒绝'"
            />
          </el-select>
        </div>
        <div class="item item2">
          <el-select
            v-model="rule.protocol"
            placeholder="请选择"
            style="width: 90%"
            size="mini"
            @change="protocolChange($event, rule)"
          >
            <el-option
              v-for="item in protocolOptions"
              :key="item.label"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </div>
        <div class="item item3">
          <el-input
            v-model="rule.portRange"
            size="mini"
            style="width: 94%"
            placeholder="例：22或22,24或22/30"
            :disabled="
              (isCloudAliyun && rule.protocol === 'ALL') ||
                rule.protocol === 'ICMP'
            "
          />
        </div>
        <div class="item item4">
          <el-input
            v-model="rule.authObj"
            size="mini"
            style="width: 94%"
            placeholder="例：0.0.0.0/0"
          />
        </div>
        <div class="item item5">
          <el-button
            style="color: #f66173"
            type="text"
            size="mini"
            @click="deleteRule(index)"
          >
            删除</el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import resSelectorMixin from '@/views/mixin/resSelector.js'
import { getRegionList, queryVPC } from '@/api/cn-resource'
import { isCloudPublic } from '@/utils/constant'
import { isEmptyString } from '@/utils'

const NAME_RULE =
  '长度为2-128个字符，只可包含特殊字符中的“.”、“_”、“-”和“:”，且不能以特殊字符及数字开头'

const getDefaultRule = () => {
  return {
    policy: '允许', // 授权策略
    protocol: '', // 协议类型
    portRange: '', // 端口范围
    authObj: '' // 授权对象
  }
}

export default {
  name: 'NsgForm',
  components: {},
  mixins: [resSelectorMixin],
  props: {
    scene: {
      type: String,
      default: 'create'
    },
    info: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      nameRule: NAME_RULE,
      skipGetCloudAccount: true,
      cloudProviderType: 'public',
      networkOptions: [],
      regionOptions: [],
      form: {
        cloudProvider: '',
        cloudAccountName: '',
        name: '',
        cpRegionId: '', // 区域
        cpVpcId: '', // 网络
        desc: '',
        pushRules: [],
        popRules: []
      },
      // 校验规则
      rules: {
        cloudProvider: [
          { required: true, message: '请选择云服务商', trigger: 'change' }
        ],
        cloudAccountName: [
          { required: true, message: '请选择云账户', trigger: 'change' }
        ],
        name: [
          { required: true, message: '请输入安全组名称', trigger: 'blur' },
          {
            pattern: /^(?![_\-\.\:0-9])[\u4e00-\u9fa5\-\.\:_a-zA-Z0-9]{2,128}$/,
            message: NAME_RULE
          }
        ],
        cpRegionId: [
          { required: true, message: '请选择区域', trigger: 'change' }
        ],
        cpVpcId: [{ required: true, message: '请选择网络', trigger: 'change' }]
      },
      activeTab: 'push',
      protocolOptions: [
        {
          label: 'TCP',
          value: 'TCP'
        },
        {
          label: 'UDP',
          value: 'UDP'
        },
        {
          label: 'ICMP',
          value: 'ICMP'
        }
      ],
      policyOptions: [
        {
          label: '允许',
          value: '允许'
        },
        {
          label: '拒绝',
          value: '拒绝'
        }
      ]
    }
  },
  computed: {
    /**
     * @description: 私有云
     * @return {*}
     */
    isCloudPrivate() {
      return !isCloudPublic(this.form.cloudProvider)
    },
    /**
     * @description: 是否阿里云
     * @return {*}
     */
    isCloudAliyun() {
      return this.form.cloudProvider === '阿里云'
    },
    currentRules() {
      return this.activeTab === 'push'
        ? this.form.pushRules
        : this.form.popRules
    },
    /**
     * @description: 网络相关参数
     * @return {*}
     */
    vpcParam() {
      return {
        cloudProvider: this.form.cloudProvider,
        cloudAccountName: this.form.cloudAccountName,
        cpRegionId: this.form.cpRegionId
      }
    }
  },
  watch: {
    /**
     * @description: 监听
     * @return {*}
     */
    info: {
      handler(newVal) {
        if (newVal) {
          this.form = Object.assign(this.form, this.info)
        }
      },
      immediate: true,
      deep: true
    },
    /**
     * @description: 监听网络相关参数
     * @return {*}
     */
    vpcParam: {
      handler(newVal) {
        if (
          newVal.cloudProvider &&
          newVal.cloudAccountName &&
          newVal.cpRegionId
        ) {
          this.getVPCList()
        }
      },
      immediate: true,
      deep: true
    },
    /**
     * @description: 云商监听
     * @return {*}
     */
    'form.cloudProvider': {
      handler(newVal) {
        if (newVal) {
          // 获取区域
          this.getRegionList()
          // 处理规则协议
          if (this.isCloudAliyun) {
            // 阿里云 协议类型 多一个 全部
            this.protocolOptions.unshift({
              label: '全部',
              value: 'ALL'
            })
          }
        }
      },
      immediate: true
    }
  },
  mounted() {},
  methods: {
    /**
     * @description: 协议选择
     * @param {*} val
     * @param {*} rule
     * @return {*}
     */
    protocolChange(val, rule) {
      if (this.isCloudAliyun && val === 'ALL') {
        // 阿里云 且 协议类型 选择了 全部
        rule.portRange = '-1/-1'
      } else if (val === 'ICMP') {
        if (this.isCloudPrivate) {
          val.portRange = ''
        } else if (this.isCloudAliyun) {
          val.portRange = '-1/-1'
        }
      }
    },
    /**
     * @description: 删除规则
     * @param {*} index
     * @return {*}
     */
    deleteRule(index) {
      if (this.activeTab === 'push') {
        this.form.pushRules.splice(index, 1)
      } else {
        this.form.popRules.splice(index, 1)
      }
    },
    /**
     * @description: 添加规则
     * @return {*}
     */
    addRule() {
      if (this.activeTab === 'push') {
        const pushRules = JSON.parse(JSON.stringify(this.form.pushRules))
        pushRules.unshift(getDefaultRule())
        this.form.pushRules = pushRules
      } else {
        const popRules = JSON.parse(JSON.stringify(this.form.popRules))
        popRules.unshift(getDefaultRule())
        this.form.popRules = popRules
      }
    },
    /**
     * @description: 获取区域
     * @return {*}
     */
    getRegionList() {
      getRegionList({
        keyword: this.form.cloudProvider,
        pageNum: 1,
        pageSize: 100
      }).then((res) => {
        if (res.data) {
          this.regionOptions = Array.isArray(res.data.data)
            ? res.data.data
            : []
        } else {
          this.regionOptions = []
        }
      })
    },
    /**
     * @description: 区域变化
     * @param {*} val
     * @return {*}
     */
    regionChange(val) {
      this.form.cpVpcId = ''
    },
    /**
     * @description: 云账户切换
     * @param {*} val
     * @return {*}
     */
    cloudAccountNameChange(val) {
      this.form.cpVpcId = ''
    },
    /**
     * @description: 获取网络
     * @return {*}
     */
    getVPCList() {
      queryVPC({
        cloudProvider: this.form.cloudProvider,
        cloudAccountName: this.form.cloudAccountName,
        region: this.form.cpRegionId
      }).then((res) => {
        this.networkOptions = Array.isArray(res.data) ? res.data : []
      })
    },
    /**
     * @description: 校验规则
     * @return {*}
     */
    validateRules() {
      for (const element of this.form.pushRules) {
        for (const key of Object.keys(element)) {
          if (isEmptyString(element[key])) {
            this.activeTab = 'push'
            this.$message.warning('规则字段不能为空')
            return false
          }
        }
      }
      for (const element of this.form.popRules) {
        for (const key of Object.keys(element)) {
          if (isEmptyString(element[key])) {
            this.activeTab = 'pop'
            this.$message.warning('规则字段不能为空')
            return false
          }
        }
      }
      return true
    },
    /**
     * @description: 校验
     * @return {*}
     */
    validateForm(callback) {
      this.$refs.form.validate((valid, obj) => {
        if (valid) {
          const rulesValid = this.validateRules()
          if (rulesValid) {
            callback(this.form)
          }
        }
      })
    }
  }
}
</script>

<style lang="less" scoped>
@import "@/assets/css/common.less";
.nsg-form-ctn {
  .rule-wrapper {
    .row {
      margin-top: 7px;
      display: flex;
      align-items: center;
      box-sizing: border-box;
      .item {
        flex: 3;
        box-sizing: border-box;
      }
      .item5 {
        flex: 1;
      }
      .item1 {
        flex: 1.8;
        padding-left: 6px;
      }
      .item2 {
        flex: 2;
      }
      &.title {
        background-color: rgb(243, 243, 243);
        height: 30px;
      }
    }
  }
}
</style>
